﻿using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.Events;

namespace ZXthex.CodingUI
{
    public class VerticalScrollArea : BaseCodingUI
    {
        public class ScrollAreaItem
        {
            public Toggle toggle { get; private set; }
            public LayoutElement layout { get; private set; }
            public Text childText { get; private set; }

            Image background;
            Image selectedBackground;
            Image front;

            public ScrollAreaItem(Toggle toggle, LayoutElement layout, Text childText, Image background, Image selectedBackground, Image front)
            {
                this.toggle = toggle;
                this.layout = layout;
                this.childText = childText;
                this.background = background;
                this.selectedBackground = selectedBackground;
                this.front = front;

            }
            public bool hightRevertColor
            {
                get
                {
                    return front.material != null && front.material.name == CodingPool.GetHightlightRevertiMaterial().name;
                }
                set
                {
                    var mat = CodingPool.GetHightlightRevertiMaterial();
                    if ((front.material != null && front.material.name == mat.name) == value)
                    {

                    }
                    else if (value)
                    {
                        front.material = mat;
                    }
                    else
                    {
                        front.material = null;
                    }
                }
            }

            public Color frontColor
            {
                get
                {
                    return toggle.colors.highlightedColor;
                }
                set
                {
                    var cs = toggle.colors;
                    cs.highlightedColor = value;
                    cs.pressedColor = value;
                    toggle.colors = cs;
                }
            }

            public Color backgroundColor
            {
                get
                {
                    return background.color;
                }
                set
                {
                    background.color = value;
                }
            }

            public Color selectedBackgroundColor
            {
                get
                {
                    return selectedBackground.color;
                }
                set
                {
                    selectedBackground.color = value;
                }
            }
        }


        VerticalScrollArea() { }

        public ScrollRect scrollRect { get; private set; }
        public ScrollAreaItem templateItem { get; private set; }
        
        public event UnityAction<Toggle> onSelectItem = (x) => { };

        private ToggleGroup tgroup;
        public bool allowAllOff
        {
            get
            {
                return tgroup.allowSwitchOff;
            }
            set
            {
                tgroup.allowSwitchOff = value;
            }
        }


        public static VerticalScrollArea Instantiate(Transform parent = null, float preferedHeight = 40)
        {

            var img = new GameObject("Vertical Scroll Area", typeof(RectTransform)).AddComponent<Image>();
            img.sprite = CodingPool.GetSquare();
            img.type = Image.Type.Sliced;
            img.transform.SetParent(parent);

            ScrollRect sr = img.gameObject.AddComponent<ScrollRect>();

            Image viewport = new GameObject("Viewport", typeof(RectTransform)).AddComponent<Image>();
            viewport.gameObject.AddComponent<Mask>().showMaskGraphic = false;
            viewport.transform.SetParent(sr.transform);

            SetDefaultRectTransform(sr.transform as RectTransform);

            viewport.rectTransform.pivot = new Vector2(0, 1);

            var content = new GameObject("Content").AddComponent<RectTransform>();
            content.SetParent(viewport.transform);
            content.anchorMin = Vector2.up;
            content.anchorMax = Vector2.one;
            content.pivot = new Vector2(0.5f, 1f);
            content.anchoredPosition = new Vector2();
            content.sizeDelta = new Vector2(0, 300);

            var vlg = content.gameObject.AddComponent<VerticalLayoutGroup>();
            vlg.childForceExpandHeight = false;
            vlg.padding = new RectOffset(2, 2, 2, 2);

            var csf = content.gameObject.AddComponent<ContentSizeFitter>();
            csf.verticalFit = ContentSizeFitter.FitMode.PreferredSize;

            var tg = content.gameObject.AddComponent<ToggleGroup>();
            tg.allowSwitchOff = true;


            sr.horizontal = false;
            sr.vertical = true;
            sr.viewport = viewport.rectTransform;
            sr.content = content;

            var item = new GameObject("Item", typeof(RectTransform)).AddComponent<Toggle>();
            var le = item.gameObject.AddComponent<LayoutElement>();
            le.preferredHeight = preferedHeight;

            item.transform.SetParent(content);
            item.transform.localScale = Vector3.one;

            var bg = new GameObject("Background", typeof(RectTransform)).AddComponent<Image>();
            bg.transform.SetParent(item.transform);
            bg.transform.localScale = Vector3.one;
            bg.rectTransform.anchorMin = Vector2.zero;
            bg.rectTransform.anchorMax = Vector2.one;
            bg.rectTransform.anchoredPosition = Vector2.zero;
            bg.rectTransform.sizeDelta = Vector2.zero;

            var sbg = new GameObject("Selected Background", typeof(RectTransform)).AddComponent<Image>();
            sbg.transform.SetParent(item.transform);
            sbg.transform.localScale = Vector3.one;
            sbg.rectTransform.anchorMin = Vector2.zero;
            sbg.rectTransform.anchorMax = Vector2.one;
            sbg.rectTransform.anchoredPosition = Vector2.zero;
            sbg.rectTransform.sizeDelta = Vector2.zero;
            sbg.color = new Color(0.5f, 0.5f, 1.0f, 1.0f);

            var customLayout = new GameObject("Custom Layout").AddComponent<RectTransform>();
            customLayout.SetParent(item.transform);
            customLayout.localScale = Vector3.one;
            customLayout.anchorMin = Vector2.zero;
            customLayout.anchorMax = Vector2.one;
            customLayout.anchoredPosition = Vector2.zero;
            customLayout.sizeDelta = Vector2.zero;

            var desc = CreateTextGameObject();
            desc.name = "Description";
            desc.alignment = TextAnchor.MiddleCenter;
            desc.rectTransform.SetParent(item.transform);
            desc.transform.localScale = Vector3.one;
            desc.rectTransform.anchorMin = Vector2.zero;
            desc.rectTransform.anchorMax = Vector2.one;
            desc.rectTransform.anchoredPosition = Vector2.zero;
            desc.rectTransform.sizeDelta = Vector2.zero;
            desc.fontSize = UIHelper.GetRecommandFontSizeWithHeight((int)preferedHeight);

            var itemHighlight = new GameObject("Item Highlight", typeof(RectTransform)).AddComponent<Image>();
            itemHighlight.transform.SetParent(item.transform);
            itemHighlight.transform.localScale = Vector3.one;
            itemHighlight.rectTransform.anchorMin = Vector2.zero;
            itemHighlight.rectTransform.anchorMax = Vector2.one;
            itemHighlight.rectTransform.anchoredPosition = Vector2.zero;
            itemHighlight.rectTransform.sizeDelta = Vector2.zero;
            itemHighlight.material = CodingPool.GetHightlightRevertiMaterial();

            item.targetGraphic = itemHighlight;
            var cs = item.colors;
            cs.highlightedColor  = cs.pressedColor = new Color(0,0,1,0.6f);

            cs.normalColor = Color.clear;
            cs.fadeDuration = 0.0f;
            item.colors = cs;
            item.isOn = false;
            item.group = tg;
            var nav = item.navigation;
            nav.mode = Navigation.Mode.None;
            item.navigation = nav;
            item.graphic = sbg;


            item.gameObject.SetActive(false);

            


            var scrollbar = new GameObject("Scrollbar", typeof(RectTransform),typeof(Image)).AddComponent<Scrollbar>();
            scrollbar.direction = Scrollbar.Direction.BottomToTop;

            var slidingArea = new GameObject("Sliding Area").AddComponent<RectTransform>();
            var handle = new GameObject("Handle", typeof(RectTransform)).AddComponent<Image>();
            scrollbar.transform.SetParent(sr.transform);
            scrollbar.transform.localScale = Vector3.one;


            handle.transform.SetParent(slidingArea);
            handle.transform.localScale = Vector3.one;
            slidingArea.SetParent(scrollbar.transform);
            slidingArea.localScale = Vector3.one;

            handle.rectTransform.sizeDelta = new Vector2(14, 14);
            slidingArea.anchorMin = Vector2.zero;
            slidingArea.anchorMax = Vector2.one;

            slidingArea.sizeDelta = new Vector2(-20,-20);

            scrollbar.handleRect = handle.rectTransform;
            scrollbar.targetGraphic = handle;
            sr.verticalScrollbar = scrollbar;
            sr.verticalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;

            sr.movementType = UnityEngine.UI.ScrollRect.MovementType.Clamped;
            const float sensitivity = 8;
            sr.scrollSensitivity = sensitivity;
            sr.decelerationRate = 0.01f;
            sr.onValueChanged.AddListener((v) =>
            {
                if (Input.mouseScrollDelta.y != 0)
                {
                    if (sr.velocity.y > -480 && sr.velocity.y < 480)
                        sr.velocity -= Input.mouseScrollDelta * 40;
                    sr.scrollSensitivity = Mathf.Lerp(sensitivity, 120, Mathf.Abs(sr.velocity.y) / 400);
                }
                else
                {
                    sr.scrollSensitivity = sensitivity;
                }
            });

            var srt = (scrollbar.transform as RectTransform);
            srt.anchorMin = new Vector2(1, 0);
            srt.anchorMax = new Vector2(1, 1);
            srt.sizeDelta = new Vector2(20,0);
            srt.anchoredPosition = new Vector2();
            srt.pivot = new Vector2(1, 0.5f);

            var simg = srt.GetComponent<Image>();
            simg.sprite = CodingPool.GetSquare();
            simg.color = new Color(0.9f, 0.9f, 0.9f, 1.0f);
            simg.type = Image.Type.Sliced;


            handle.color = new Color(0.8f, 0.8f, 0.8f, 1.0f);
            handle.type = Image.Type.Sliced;

            return new VerticalScrollArea { scrollRect = sr, tgroup = tg,
                templateItem = new ScrollAreaItem (
                    toggle:item, childText : desc, layout : le ,
                    background:bg, selectedBackground:sbg, front:itemHighlight

                ) };
        }

        const int ITEM_CUSTOM_CHILD_INDEX = 2;
        const int ITEM_TEXT_CHILD_INDEX = 3;

        private GameObject AddItemInternal(string text, UnityAction<RectTransform> additionLayout)
        {
            var item = Object.Instantiate(scrollRect.content.GetChild(0).gameObject);
            item.transform.SetParent(scrollRect.content);
            item.transform.GetChild(ITEM_TEXT_CHILD_INDEX).GetComponent<Text>().text = text;

            var t = item.GetComponent<Toggle>();
            t.onValueChanged.AddListener((v) =>
            {
                if (v)
                {
                    onSelectItem.Invoke(t);
                }
            });

            if (additionLayout != null) additionLayout.Invoke(item.transform.GetChild(ITEM_CUSTOM_CHILD_INDEX) as RectTransform);

            item.SetActive(true);
            return item;
        }

        public void AddItem(string text="", UnityAction<RectTransform> additionLayout = null)
        {
            AddItemInternal(text, additionLayout);
        }

        public void AddItem(UnityAction<RectTransform> additionLayout, string text = "")
        {
            AddItemInternal(text, additionLayout);
        }

        public void InsertItemAt(int index, string text = "", UnityAction<RectTransform> additionLayout = null)
        {
            var item =  AddItemInternal(text, additionLayout);
            item.transform.SetSiblingIndex(index+1);
        }

        public void InsertItemAt(int index, UnityAction<RectTransform> additionLayout, string text = "")
        {
            var item = AddItemInternal(text, additionLayout);
            item.transform.SetSiblingIndex(index+1);
        }

        public void RemoveItemAt(int index)
        {
            if (index < 0) return;

            var item = scrollRect.content.GetChild(index + 1).gameObject;
            Object.Destroy(item);
        }

        public int ItemCount { get { return scrollRect.content.childCount - 1; } }

        public void ClearItems()
        {
            for (int i = 1; i < scrollRect.content.childCount; i++)
            {
                Object.Destroy(scrollRect.content.GetChild(i).gameObject);
            }
        }
    }
}